package org.jeecg.modules.paycenter.pay.util;

import org.apache.commons.lang.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.XmlUtils;
import org.jeecg.modules.paycenter.channel.bankdocking.dto.*;
import org.jeecg.modules.paycenter.exception.BankReceiveException;
import org.jeecg.modules.paycenter.exception.BankSendException;
import org.jeecg.modules.wlhy.hyconfig.entity.HyConfig;
import org.jeecg.modules.wlhy.utils.BankTypeUtil;
import org.jeecg.modules.wlhy.utils.HyConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.math.BigDecimal;

//@Service
public class NhBankUtils {
    private static Logger logger = LoggerFactory.getLogger("bankLog");
    private static String _cur = "01";

    public static String sendDataStr(String data) throws Exception {
        data = String.format("1%-6s", data.getBytes("gbk").length) + data;
        SocketClient client = new SocketClient();
        HyConfig config = HyConfigUtils.getConfig();
        String nhbankPort = config.getNhbankPort();
        if (!client.conn(config.getNhbankIp(), Integer.parseInt(nhbankPort))) {
            logger.info("交易失败:连接错误");
            throw new BankSendException("交易失败:连接错误");
        }
        if (!client.sendData(data)) {
            logger.info("交易失败:发送数据失败");
            throw new BankSendException("交易失败:发送数据失败");
        }
        try {
            String ret = client.receiveData();
            if (ret != null && ret.length() > 7) {
                ret = ret.substring(7);
                return ret;
            }
        } catch (Exception e) {
            //需要做后续处理
            logger.error("交易失败：接收数据失败");
            throw new BankReceiveException("交易失败：接收数据失败");
        }
        return "";
    }

    /**
     *JeecgBootException 不需要做后续处理
     * BankException 需要做后续处理，通过reqSeqNo流水号，查询交易状态及结果
     */
    public static RespPacket sendData(ReqPacket packet) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        packet.setCorpNo(config.getNhbankCorpno());
        String data = null;
        try {
            data = XmlUtils.converTomXml(packet);
            logger.info("发送数据：" + data);
        }catch (Exception e){
            logger.info("交易失败:数据转换错误");
            throw new JeecgBootException("交易失败:数据转换错误");
        }
        String ret = sendDataStr(data);
        if(StringUtils.isEmpty(ret)){
            logger.info("交易失败：接收数据异常");
            throw new BankReceiveException("交易失败：接收数据异常");
        }
        logger.info("接收数据：" + ret.replaceAll("\n|\t|\r",""));
        try {
            RespPacket retPacket = XmlUtils.converyToJavaBean(ret, RespPacket.class);
            if(retPacket != null){
               if("2002".equals(retPacket.getRespCode())){
                   throw new JeecgBootException(retPacket.getRespInfo());
               }
            }
            return retPacket;
        }catch (Exception e){
            logger.info("交易失败：数据处理异常");
            throw new BankReceiveException("交易失败：数据处理异常");
        }
    }

    //查询账号余额
    public static RespPacket getAccountBalance(String accNo , String prov ) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        if(!config.getNhbankIzUse()){
            throw new Exception("未开通服务");
        }

        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRA06");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbCur("01");
        packet.setCmp(cmp);
        return sendData(packet);
    }

    //对外 汇兑-单笔对公  支付  提现
    public static RespPacket singleExchange(String reqSeqNo, String dbProv ,String crProv ,
                                      String dbAccNo,String dbLogAccNo,String dbAccName,
                                      String crAccNo ,String crAccName ,
                                      BigDecimal amt , String bankType, String postscript) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        if(!config.getNhbankIzUse()){
            throw new Exception("未开通服务");
        }
        ReqPacket packet = new ReqPacket();
        packet.setReqSeqNo(reqSeqNo);
        packet.setCCTransCode("CFRT02");
        Cmp cmp = new Cmp();
        packet.setAmt(amt);
        cmp.setDbProv(dbProv);
        cmp.setDbAccNo(dbAccNo);
        cmp.setDbCur("01");
        cmp.setDbLogAccNo(dbLogAccNo);

        cmp.setCrAccNo(crAccNo);
        cmp.setCrProv(crProv);
        cmp.setCrCur("01");
        cmp.setCrLogAccNo("");
        cmp.setConFlag("1");
//        cmp.setConFlag("0");
        packet.setCmp(cmp);

        Corp corp = new Corp();
        corp.setBookingFlag("0");
        corp.setBookingDate("");
        corp.setBookingTime("");
        corp.setUrgencyFlag("0");
        if("ABOC".equals(bankType)) {
            corp.setOthBankFlag("0");
            corp.setCrBankNo("");
        }else {
            String crbankNo = BankTypeUtil.getBankNo(bankType);
            if(StringUtils.isEmpty(crbankNo)){
                throw new JeecgBootException("未获取到行号");
            }
            corp.setOthBankFlag("1");
            corp.setCrBankNo(crbankNo);
        }

        corp.setCrAccName(crAccName);
        corp.setCrBankName("");


        corp.setDbAccName(dbAccName);
        corp.setPostscript(postscript);
        packet.setCorp(corp);
        return sendData(packet);
    }

    public static RespPacket singleExchange2(String reqSeqNo, String dbProv ,String crProv ,
                                     String dbAccNo,String dbLogAccNo,String dbAccName,
                                     String crAccNo , String crLogAccNo ,String crAccName ,
                                     BigDecimal amt , String bankType, String postscript) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        if(!config.getNhbankIzUse()){
            throw new Exception("未开通服务");
        }
        ReqPacket packet = new ReqPacket();
        packet.setReqSeqNo(reqSeqNo);
        packet.setCCTransCode("CFRT02");
        Cmp cmp = new Cmp();
        packet.setAmt(amt);
        cmp.setDbProv(dbProv);
        cmp.setDbAccNo(dbAccNo);
        cmp.setDbCur("01");
        cmp.setDbLogAccNo(dbLogAccNo);

        cmp.setCrAccNo(crAccNo);
        cmp.setCrProv(crProv);
        cmp.setCrCur("01");
        cmp.setCrLogAccNo(crLogAccNo);
        cmp.setConFlag("1");
//        cmp.setConFlag("0");
        packet.setCmp(cmp);

        Corp corp = new Corp();
        corp.setBookingFlag("0");
        corp.setBookingDate("");
        corp.setBookingTime("");
        corp.setUrgencyFlag("0");
        if("ABOC".equals(bankType)) {
            corp.setOthBankFlag("0");
            corp.setCrBankNo("");
        }else {
            String crbankNo = BankTypeUtil.getBankNo(bankType);
            if(StringUtils.isEmpty(crbankNo)){
                throw new JeecgBootException("未获取到行号");
            }
            corp.setOthBankFlag("1");
            corp.setCrBankNo(crbankNo);
        }

        corp.setCrAccName(crAccName);
        corp.setCrBankName("");


        corp.setDbAccName(dbAccName);
        corp.setPostscript(postscript);
        packet.setCorp(corp);
        return sendData(packet);
    }

    //银行内部转账专用(汇兑-单笔对公)
    public static RespPacket insideExchange( String reqSeqNo,String dbProv ,String crProv ,
                                      String dbAccNo,String dbLogAccNo,String dbAccName,
                                      String crAccNo ,String crAccName ,
                                      BigDecimal amt,String postscript) throws Exception {
        return singleExchange(reqSeqNo, dbProv, crProv,
                dbAccNo, dbLogAccNo, dbAccName,
                crAccNo, crAccName,
                amt, "ABOC", postscript
        );
    }

    //司机提现
    public static RespPacket tx(String reqSeqNo, String dbProv ,String crProv ,
                         String dbAccNo,String dbLogAccNo,String dbAccName,
                         String crAccNo ,String crAccName ,
                         BigDecimal amt ,  String bankType  ) throws Exception {
        if(StringUtils.isEmpty(bankType)){
            throw new JeecgBootException("银行代码错误");
        }
        return  singleExchange(reqSeqNo , dbProv,crProv,
                dbAccNo,dbLogAccNo,dbAccName,
                crAccNo,crAccName,
                amt,bankType,"提现"
        );
    }

    /**查询金融交易处理状态
     * 返回值 TransSta
     * 1 待复核 表示等待复核，交易还没有发到后台，除 了极少数客户提出 ERP 录入客户端复核 的需求外，其他客户的 ERP 交易是不需 要复核直接提交后台的，因此不会遇到这 个状态
     * 2 未复核完成 同上，表示还未完全通过复核环节
     * 3 正在发送 此为临时状态，银行系统会及时更新为最 终的处理状态
     * 4 处理成功 此为最终状态，即交易成功
     * 5 交易失败 此为最终状态，即交易失败
     * 6 落地待处理 交易等待柜员人工处理，人工处理完后系 统会自动更新为 4（成功）或 5（失败）
     * 7 预约受理 客户使用了预约功能，系统等待到了预约 时间再提交后台
     * 8 交易取消 此状态比较少见，可视为失败
     * 9 交易状态未知 需要继续查证
     * @param serialNo
     * @return
     * @throws IOException
     */
    public static RespPacket getExchangeStatus(String serialNo ) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRT71");
        Cme cme = new Cme();
        cme.setSerialNo(serialNo);
        packet.setCme(cme);
        return sendData(packet);
    }

    //查询账簿余额
    public static RespPacket getAccountBookBalance(String accNo , String prov , String dbLogAccNo) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        if(!config.getNhbankIzUse()){
            throw new Exception("未开通服务");
        }
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRA20");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbCur("01");
        cmp.setDbLogAccNo(dbLogAccNo);
        packet.setCmp(cmp);
        return sendData(packet);
    }

    /**
     * 子账户之间余额调整
     * @param accNo
     * @param prov
     * @param cur
     * @param dbLogAccNo
     * @param crLogAccNo
     * @return
     * @throws Exception
     */
    public static RespPacket adjustAccountBookBalance(String accNo ,
                                                      String prov ,
                                                      BigDecimal amt ,
                                                      String dbLogAccNo,
                                                      String crLogAccNo,
                                                      String postScript) throws Exception {

        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CFRA01");
        packet.setAmt(amt);
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        //货币码，默认为人民币
        cmp.setDbCur("01");
        cmp.setDbLogAccNo(dbLogAccNo);
        cmp.setCrLogAccNo(crLogAccNo);

        Corp corp = new Corp();
        corp.setPostscript(postScript);

        Channel channel = new Channel();
        channel.setOrgDate(DateUtils.getDate("yyyyMMdd"));

        packet.setCmp(cmp);
        packet.setCorp(corp);
        packet.setChannel(channel);
        return sendData(packet);
    }

    /**
     * 查询单账户明细（含账簿号）
     * 账簿号 = 账号 + (10位)账簿编号
     */
    public static RespPacket getAccountAndBookInfo(String accNo , String prov , String cur , String startDate , String endDate) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRA18");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbCur(cur);
        Corp corp = new Corp();
        corp.setStartDate(startDate);
        corp.setEndDate(endDate);

        packet.setCmp(cmp);
        packet.setCorp(corp);
        return sendData(packet);
    }

    /**
     * 查询账户历史余额
     */
    public static RespPacket getAccountHistoryBalance(String accNo , String prov , String cur ,String startDate ,  String endDate) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRC17");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbCur(cur);
        Corp corp = new Corp();
        corp.setStartDate(startDate);
        corp.setEndDate(endDate);

        packet.setCmp(cmp);
        packet.setCorp(corp);
        return sendData(packet);
    }

    /**
     * 查询账簿历史余额
     */
    public static RespPacket getAccountBookHistoryBalance(String accNo , String prov , String dbLogAccNo ,String startDate ,  String endDate) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRB11");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbLogAccNo(dbLogAccNo);
        cmp.setDbCur("01");
        Corp corp = new Corp();
        corp.setStartDate(startDate);
        corp.setEndDate(endDate);

        packet.setCmp(cmp);
        packet.setCorp(corp);
        return sendData(packet);
    }

    /**
     * 多级账薄明细查询
     */
    public static RespPacket getAccountBookDetail(String accNo , String prov , String dbLogAccNo ,String startDate ,  String endDate) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRD01");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbLogAccNo(dbLogAccNo);
        cmp.setCrLogAccNo(dbLogAccNo);
        cmp.setDbCur("01");
        Corp corp = new Corp();
        corp.setStartDate(startDate);
        corp.setEndDate(endDate);
        Cme cme=new Cme();
        cme.setContLast("");
        packet.setCmp(cmp);
        packet.setCorp(corp);
        packet.setCme(cme);
        return sendData(packet);
    }

    //卡号、户名一致性校验（CMLR49）
    public static RespPacket checkAccount(String accNo , String prov , String cur , String prdNam) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CMLR49");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbCur(cur);

        Pds pds = new Pds();
        pds.setPrdNam(prdNam);
        packet.setCmp(cmp);
        packet.setPds(pds);
        return sendData(packet);
    }

    //增加多级账簿（CMLT40）
    public static RespPacket AddAccountBook(String dbLogAccName ,String dbLogAccNo ) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CMLT40");
        Cmp cmp = new Cmp();
        cmp.setDbProv(config.getNhbankProv());
        cmp.setDbAccNo(config.getNhbankAccno());
        cmp.setDbCur(_cur);
        cmp.setCrLogAccNo("0000000000");//多级账簿上级编号
        cmp.setDbLogAccNo(dbLogAccNo);//多级账簿编号
        cmp.setLogAccBkOInd("0");//多级账簿输出标志 ,0-不输出 1-按日 2-按月
//        cmp.setAuthAmt("0");//账簿超额额度,
//        cmp.setStatInd("0");//统计标识

        Corp corp = new Corp();
        corp.setDbLogAccName(dbLogAccName);//多级账簿名称
        corp.setIntTyp("1");//计息方式, 0-不计息滚积数 1-借贷方分 别计息
        corp.setDbIntType("V");//借方利息类型 , F-固定（自定义利率） V-可变（挂牌利率）
//        corp.setDbRit("");//借方自定义利率 ,当借方利息类型为F-固 定（自定义 利率）时为 必输项
        corp.setDbRatType("00002000");//借方利率代码,当借方利息 类型为 V 可 变（挂牌利 率）为必输 取值详见附 录 B 字典利 率代码 （360）
        corp.setDbAddType("1");//借方利率浮动方 式,当借方利息 类型为 V 可 变（挂牌利 率）为必输 1-浮点 2-浮比
//        corp.setDbRatPct("");//借方浮比,当借方利率浮动方式为 2-浮比时为必输
        corp.setDbRatAdd("0");//借方浮点,借方利率浮 动方式为 1- 浮点时为必 输
        corp.setCrIntType("V");//贷方利息类型,F-固定（自 定义利率） V-可变（挂 牌利率）
//        corp.setCrRit("");//贷方自定义利率,当贷方利息 类型为F-固 定（自定义 利率）时为 必输项
        corp.setCrRatType("00002000");//贷方利率代码,当贷方利息 类型为 V 可 变（挂牌利 率）为必输 取值详见字 典
        corp.setCrAddType("1");//贷方利率浮动方 式,1-浮点 2-浮比
//        corp.setCrRatPct("");//贷方浮比,当贷方利率 浮动方式为 2-浮比时为 必输
        corp.setCrRatAdd("0");//贷方浮点,当贷方利率 浮动方式为 1-浮点时为 必输
        corp.setActInf("0"); //存款动帐通知书 生成标识,0-不输出 1-输出
        corp.setPmtHd("02");//账簿支取方式,02-以收定 支（锁定值）


        packet.setCmp(cmp);
        packet.setCorp(corp);
        return sendData(packet);
    }

    //删除单个多级账簿
    public static RespPacket deleteAccountBook(String dbLogAccNo ) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CMLT41");
        Cmp cmp = new Cmp();
        cmp.setDbProv(config.getNhbankProv());
        cmp.setDbAccNo(config.getNhbankAccno());
        cmp.setDbCur(_cur);
        cmp.setDbLogAccNo(dbLogAccNo);//多级账簿编号
        packet.setCmp(cmp);
        return sendData(packet);
    }

    //修改多级账簿名称
    public static RespPacket editAccountBookName(String dbLogAccNo , String newDbLogAccName ) throws Exception {
        HyConfig config = HyConfigUtils.getConfig();
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CFRB90");
        Cmp cmp = new Cmp();
        cmp.setDbProv(config.getNhbankProv());
        cmp.setDbAccNo(config.getNhbankAccno());
        cmp.setDbCur(_cur);
        cmp.setDbLogAccNo(dbLogAccNo);//多级账簿编号

        Corp corp = new Corp();
        corp.setDbLogAccName2(newDbLogAccName);

        packet.setCmp(cmp);
        packet.setCorp(corp);
        return sendData(packet);
    }

    //查询回单信息 CQRC16
    public static RespPacket getAccountHdInfo(String accNo , String prov , String cur , String dbLogAccNo , String startDate, String endDate ) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRC16");
        Cmp cmp = new Cmp();
        cmp.setDbProv(prov);
        cmp.setDbAccNo(accNo);
        cmp.setDbCur(cur);
        cmp.setDbLogAccNo(dbLogAccNo);//多级账簿编号

        Corp corp = new Corp();
        corp.setStartDate(startDate);
        corp.setEndDate(endDate);
        corp.setEndDate(endDate);
        corp.setFileCompress("0"); //不压缩

        packet.setCmp(cmp);
        packet.setCorp(corp);
        return sendData(packet);
    }

    //查询联行行号
    public static RespPacket getBankNo(String crBankName , String crBankType ) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQLT09");

        Corp corp = new Corp();
        corp.setCrBankName(crBankName);
        corp.setCrBankType(crBankType);
        packet.setCorp(corp);
        return sendData(packet);
    }
    //查询联行行号
    public static RespPacket getBankNoList(String crBankName , String crBankType ) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQLA96");

        Corp corp = new Corp();
        corp.setCrBankName(crBankName);
        corp.setCrBankType(crBankType);
        packet.setCorp(corp);
        return sendData(packet);
    }

    //查询账户明细 ruirui
    public static RespPacket getAccountDetail(String dbProv, String dbAccNo, String dbCur,
                                String startDate, String endDate, String StartTime) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQRA10");

        Cmp cmp = new Cmp();
        cmp.setDbProv(dbProv);//本方省市代码
        cmp.setDbAccNo(dbAccNo);//本方账号
        cmp.setDbCur(dbCur);//本方货币码

        Corp corp = new Corp();
        corp.setStartDate(startDate);//对方省市代码
        corp.setEndDate(endDate);//对方账号

        cmp.setStartTime(StartTime);//对方货币码

        packet.setCmp(cmp);
        packet.setCorp(corp);

        return sendData(packet);
    }
    //银行电子回单 ruirui
    public static RespPacket getBankHd(String dbProv, String dbAccNo, String dbCur,
                                     String crProv, String crAccNo, String crCur,
                                     String date, String jrnNo, BigDecimal amt) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CMRA76");

        Cmp cmp = new Cmp();
        cmp.setDbProv(dbProv);//本方省市代码
        cmp.setDbAccNo(dbAccNo);//本方账号
        cmp.setDbCur(dbCur);//本方货币码

        cmp.setCrProv(crProv);//对方省市代码
        cmp.setCrAccNo(crAccNo);//对方账号
        cmp.setCrCur(crCur);//对方货币码

        cmp.setTrDate(date);
        cmp.setJrnNo(jrnNo);

        packet.setCmp(cmp);
        packet.setAmt(amt);//交易金额
        return sendData(packet);
    }

    //下载银行行号
    public static RespPacket downloadBankNo(String bankName , String bankType) throws Exception {
        ReqPacket packet = new ReqPacket();
        packet.setCCTransCode("CQLT09");

        Corp corp = new Corp();
        corp.setCrBankName(bankName);
        corp.setCrBankType(bankType);
        packet.setCorp(corp);
        return sendData(packet);
    }

    public static void main(String[] args) throws Exception {
        HyConfig config = new HyConfig();
        config.setNhbankIzUse(true);
        config.setNhbankAccno("350001040038006");
        config.setNhbankCorpno("6613502097765409");
        config.setNhbankIp("124.70.18.92");
        config.setNhbankPort("15999");
        config.setNhbankProv("50");
        HyConfigUtils.setConfig(config);

        RespPacket respPacket = null;

        //垫付账户
        respPacket = NhBankUtils.insideExchange("112233","15","15",
                "155101040023649","","师国靖纪彦阅颖世彦阅",
                "1551010400236495550480220","师国靖纪彦阅颖世彦阅",new BigDecimal("5000"),""
                );

//        respPacket =NhBankUtils.getAccountBookBalance("155101040013566","15","5000000001");

        System.out.println(respPacket);
    }

}
